package com.lalilu.lread

import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import com.lalilu.lread.utils.*
import kotlinx.coroutines.*
import nl.siegmann.epublib.domain.Book
import nl.siegmann.epublib.epub.EpubReader
import java.util.logging.Logger

class EpubScanner private constructor(context: Context) {
    private val logger = Logger.getLogger(this.javaClass.name)
    private val contentResolver = context.contentResolver
    private val epubMMKV = EpubMMKV.getInstance(context)
    private val globalConfig = GlobalConfig.getInstance(context)
    private val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
    private val epubReader = EpubReader()
    private val threadPool = ThreadPoolUtils.newCachedThreadPool().asCoroutineDispatcher()

    fun scanFromUrisByEpubLib(list: List<Uri>, onUpdate: () -> Unit) {
        list.forEach { uri ->
            GlobalScope.launch(Dispatchers.IO) {
                contentResolver.takePersistableUriPermission(uri, takeFlags)

                val md5 = async(threadPool) {
                    val inputStream = contentResolver.openInputStream(uri)
                    val temp = MD5Util.generateFileHash(inputStream, 8)
                    inputStream?.close()
                    epubMMKV.saveByKey(temp)
                    onUpdate.invoke()
                    return@async temp
                }

                val epubBook = async(threadPool) {
                    val inputStream = contentResolver.openInputStream(uri)
                    val book = epubReader.readEpub(inputStream)
                    inputStream?.close()
                    return@async book
                }

                epubMMKV.saveBookByEpubLib(uri, epubBook.await(), md5.await())
                onUpdate.invoke()

                loadAssetsIntoCache(epubBook.await(), md5.await())
            }
        }
    }

    private suspend fun loadAssetsIntoCache(epubBook: Book, id: String) =
        withContext(Dispatchers.IO) {
            for (resource in epubBook.resources.getResourcesByMediaTypes(globalConfig.typeToLoad)) {
                async(threadPool) {
                    val name = StringUtil.getFileNameFromPathWithoutExt(resource.href)
                    var ext = StringUtil.getExtFromText(resource.href)
                    val path = "${globalConfig.cachePath}/${globalConfig.tempPrefix}${id}_$name."
                    var data = resource.data

                    if (listOf("jpg", "jpeg", "png").contains(ext)) {
                        ext = "webp"
                        data = BitmapUtil.compressBytesToFormat(
                            data,
                            60,
                            Bitmap.CompressFormat.WEBP_LOSSY
                        )
                    }
                    FileUtil.saveFile("$path$ext", data)
                }
            }
        }

    companion object {
        @Volatile
        private var instance: EpubScanner? = null

        @Throws(NullPointerException::class)
        fun getInstance(context: Context): EpubScanner {
            instance ?: synchronized(EpubScanner::class.java) {
                instance = instance ?: EpubScanner(context)
            }
            if (instance == null) throw NullPointerException() else return instance!!
        }
    }
}